package com.vincent.rpc.client.proxy;

import java.lang.reflect.Method;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.vincent.rpc.client.RpcClient;
import com.vincent.rpc.common.bean.RpcRequest;
import com.vincent.rpc.common.bean.RpcResponse;
import com.vincent.rpc.common.registry.ServiceDiscovery;

/**
 * abstract class for rpc proxy
 * @author vincent
 *
 */
public abstract class RpcProxy {

	private static final Logger LOGGER = LoggerFactory.getLogger(RpcProxy.class);
	
	private String serviceAddress;

    private ServiceDiscovery serviceDiscovery;

    public RpcProxy(String serviceAddress) {
        this.serviceAddress = serviceAddress;
    }

    public RpcProxy(ServiceDiscovery serviceDiscovery) {
        this.serviceDiscovery = serviceDiscovery;
    }
    
    /**
     * makeup the request object
     * @param method
     * @param args
     * @param serviceVersion
     * @return RpcRequest
     */
    protected RpcRequest makeupRequest(Method method, Object[] args, String serviceVersion) {
		
		RpcRequest request = new RpcRequest();
		request.setRequestId(UUID.randomUUID().toString());
        request.setInterfaceName(method.getDeclaringClass().getName());
        request.setServiceVersion(serviceVersion);
        request.setMethodName(method.getName());
        request.setParameterTypes(method.getParameterTypes());
        request.setParameters(args);
		return request;
	}

	/**
	 * get service address
	 * @param interfaceClass
	 * @param serviceVersion
	 * @return
	 */
	protected String scanServiceAddress(Class<?> interfaceClass, String serviceVersion) {
		
		
		if (this.serviceAddress != null) return this.serviceAddress;
		
		String serviceAddr = null;
		if (serviceDiscovery != null) {
            String serviceName = interfaceClass.getName();
            if (StringUtils.isNotEmpty(serviceVersion)) {
                serviceName += "-" + serviceVersion;
            }
            serviceAddr = getServiceDiscovery().discover(serviceName);
            LOGGER.debug("discover service: {} => {}", serviceName, serviceAddr);
        }
        if (StringUtils.isEmpty(serviceAddr)) {
            throw new RuntimeException("server address is empty");
        }
		return serviceAddr;
	}
    
	protected RpcResponse sendRequest(String serviceAddr, RpcRequest request) throws Exception {
		
		 String[] array = StringUtils.split(serviceAddr, ":");
         String host = array[0];
         int port = Integer.parseInt(array[1]);
         // 创建 RPC 客户端对象并发送 RPC 请求
         RpcClient client = RpcClient.getInstance(host, port);
         long time = System.currentTimeMillis();
         RpcResponse response = client.send(request);
         LOGGER.debug("time: {}ms", System.currentTimeMillis() - time);
         return response;
	}
	
//    public String getServiceAddress() {
//    	return this.serviceAddress;
//    }
	
    public ServiceDiscovery getServiceDiscovery () {
    	return this.serviceDiscovery;
    }
    
	/**
 	* create proxy with empty version
 	* @param interfaceClass
 	* @return
 	*/
	abstract public <T> T create(final Class<?> interfaceClass);
  
	/**
	 * create proxy with version
	 * @param interfaceClass
	 * @param serviceVersion
	 * @return
	 */
	abstract public <T> T create(final Class<?> interfaceClass, final String serviceVersion);
  
}
